import { defineComponent, ref, computed, watch, onMounted, onUpdated, nextTick, openBlock, createElementBlock, normalizeStyle, createElementVNode, Fragment, renderList, renderSlot } from "vue";
const _hoisted_1 = ["id"];
const _sfc_main = /* @__PURE__ */ defineComponent({
  ...{
    name: "me-virtual-list"
  },
  __name: "virtual-list",
  props: {
    arrayList: { default() {
      return [];
    } },
    itemHeight: { default: 40 },
    bufferScale: { default: 1 },
    height: { default: "100%" },
    itemGap: { default: 0 }
  },
  setup(__props, { expose: __expose }) {
    const props = __props;
    const screenHeight = ref(0);
    const start = ref(0);
    const end = ref(0);
    const containerRef = ref();
    const listRef = ref();
    const listParentRef = ref();
    let positions = [];
    const offset = ref(0);
    const list = computed(() => {
      return props.arrayList.map((item, index) => {
        return {
          index,
          item
        };
      });
    });
    const visibleCount = computed(() => {
      return Math.ceil(screenHeight.value / props.itemHeight);
    });
    const aboveCount = computed(() => {
      return Math.min(start.value, props.bufferScale * visibleCount.value);
    });
    const belowCount = computed(() => {
      return Math.min(props.arrayList.length - end.value, props.bufferScale * visibleCount.value);
    });
    const visibleData = computed(() => {
      const start0 = start.value - aboveCount.value;
      const end0 = end.value + belowCount.value;
      return list.value.slice(start0, end0);
    });
    watch(() => props.arrayList, () => {
      screenHeight.value = containerRef.value.clientHeight;
      start.value = 0;
      end.value = start.value + visibleCount.value;
      scrollTo(0);
      positions = [];
      initPositions();
    });
    onMounted(() => {
      screenHeight.value = containerRef.value.clientHeight;
      start.value = 0;
      end.value = start.value + visibleCount.value;
      initPositions();
    });
    onUpdated(() => {
      nextTick(() => {
        if (!listRef.value || listRef.value.length == 0) {
          return;
        }
        updateSize();
        const height = positions[positions.length - 1].bottom;
        listParentRef.value.style.height = height + "px";
        setStartOffset();
      });
    });
    const updateSize = () => {
      listRef.value.map((node) => {
        const rect = node.getBoundingClientRect();
        const index = Number(node.id);
        const height = rect.height + (index < positions.length - 1 ? props.itemGap : 0);
        const oldHeight = positions[index].height;
        const value = oldHeight - height;
        if (value) {
          positions[index].bottom = positions[index].bottom - value;
          positions[index].height = height;
          for (let i = index + 1; i < positions.length; i++) {
            positions[i].top = positions[i - 1].bottom;
            positions[i].bottom = positions[i].bottom - value;
          }
        }
      });
    };
    const initPositions = () => {
      for (let i = 0; i < props.arrayList.length; i++) {
        positions.push({
          index: i,
          height: props.itemHeight,
          top: i * props.itemHeight,
          bottom: (i + 1) * props.itemHeight
        });
      }
    };
    const handleScroll = () => {
      const scrollTop = containerRef.value.scrollTop;
      start.value = getStartIndex(scrollTop);
      end.value = start.value + visibleCount.value;
      setStartOffset();
    };
    const setStartOffset = () => {
      let startOffset = 0;
      if (start.value >= 1) {
        const size = positions[start.value].top - (positions[start.value - aboveCount.value] ? positions[start.value - aboveCount.value].top : 0);
        startOffset = positions[start.value - 1].bottom - size;
      }
      offset.value = startOffset;
    };
    const getStartIndex = (scrollTop = 0) => {
      return binarySearch(positions, scrollTop);
    };
    const binarySearch = (list2, value) => {
      let start2 = 0;
      let end2 = list2.length - 1;
      let tempIndex = null;
      while (start2 <= end2) {
        let midIndex = parseInt(String((start2 + end2) / 2));
        let midValue = list2[midIndex].bottom;
        if (midValue === value) {
          return midIndex + 1;
        } else if (midValue < value) {
          start2 = midIndex + 1;
        } else if (midValue > value) {
          if (tempIndex === null || tempIndex > midIndex) {
            tempIndex = midIndex;
          }
          end2 = end2 - 1;
        }
      }
      return tempIndex;
    };
    const scrollTo = (top, behavior = "auto") => {
      containerRef.value.scrollTo({ top, behavior });
    };
    const scrollBy = (top, behavior = "auto") => {
      containerRef.value.scrollBy({ top, behavior });
    };
    __expose({
      scrollTo,
      scrollBy
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        ref_key: "containerRef",
        ref: containerRef,
        class: "me-virtual-list",
        style: normalizeStyle({ height: _ctx.height }),
        onScroll: handleScroll
      }, [
        createElementVNode("div", {
          class: "me-virtual-scroll",
          ref_key: "listParentRef",
          ref: listParentRef
        }, null, 512),
        createElementVNode("div", {
          class: "me-virtual-list-inner",
          style: normalizeStyle({ transform: `translateY(${offset.value}px)` })
        }, [
          (openBlock(true), createElementBlock(Fragment, null, renderList(visibleData.value, (item) => {
            return openBlock(), createElementBlock("div", {
              ref_for: true,
              ref_key: "listRef",
              ref: listRef,
              class: "me-virtual-list-inner-list",
              style: normalizeStyle({ marginBottom: `${_ctx.itemGap}px` }),
              key: item.index,
              id: String(item.index)
            }, [
              renderSlot(_ctx.$slots, "default", {
                item: item.item
              })
            ], 12, _hoisted_1);
          }), 128))
        ], 4)
      ], 36);
    };
  }
});
export {
  _sfc_main as default
};
//# sourceMappingURL=virtual-list.vue2.mjs.map
